#include <shadow.h>
#include "thread_pool.h"
//#include "func.h"
//#include "taskque.c"
//其作用：确定发送len字节的数据

int sendn(int sockfd, const void * buff, int len)
{
    int left = len;
    const char * pbuf = (char *)buff;
    int ret = -1;
    while(left > 0) {
        ret = send(sockfd, pbuf, left, 0);
        if(ret < 0) {
            perror("send");
            return -1;
        }

        left -= ret;
        pbuf += ret;
    }
    return len - left;
}

//其作用：确定接收len字节的数据
int recvn(int sockfd, void * buff, int len)
{
    int left = len;//还剩下多少个字节需要接收
    char * pbuf = (char *)buff;
    int ret = -1;
    while(left > 0) {
        ret = recv(sockfd, pbuf, left, 0);
        if(ret == 0) {
            break;
        } else if(ret < 0) {
            perror("recv");
            return -1;
        }

        left -= ret;
        pbuf += ret;
    }
    //当退出while循环时，left的值等于0
    return len - left;
}

int user_login(int net_fd, char *logged_in_username)
{
    train_t train;
    bzero(&train, sizeof(train));
    // 接收用户名，判断合法性
    recv(net_fd, &train, sizeof(train.len) + sizeof(train.type), MSG_WAITALL);
    recv(net_fd, train.buff, train.len, MSG_WAITALL);
    struct spwd *sp = getspnam(train.buff);
    if (sp == NULL)
    {
        printf("Received login request Username illegal.\n");
        bzero(&train, sizeof(train));
        // 返回客户端
        send(net_fd, &train, sizeof(train.len) + sizeof(train.type) + train.len, MSG_NOSIGNAL);
        return -1;
    }
    char username[1000] = {0};
    strcpy(username, train.buff);
    // 提取salt
    char salt[1024] = {0};
    int idx = 0;
    for (int i = strlen(sp->sp_pwdp); i >= 0; --i)
    {
        if (sp->sp_pwdp[i] == '$')
        {
            idx = i;
            break;
        }
    }
    strncpy(salt, sp->sp_pwdp, idx + 1);
    // 返回客户端salt
    bzero(train.buff, train.len);
    train.len = strlen(salt);
    memcpy(train.buff, salt, train.len);
    send(net_fd, &train, sizeof(train.len) + sizeof(train.type) + train.len, MSG_NOSIGNAL);
    // 密码校验
    bzero(train.buff, train.len);
    recv(net_fd, &train, sizeof(train.len) + sizeof(train.type), MSG_WAITALL);
    recv(net_fd, train.buff, train.len, MSG_WAITALL);
    printf("%s\n", train.buff);
    if (strcmp(sp->sp_pwdp, train.buff) != 0)
    {
        // 密码错误
        bzero(train.buff, train.len);
        train.len = 0;
        // 返回客户端校验结果
        send(net_fd, &train, sizeof(train.len) + sizeof(train.type) + train.len, MSG_NOSIGNAL);
        return -1;
    }
    // 密码正确
    bzero(train.buff, train.len);
    strcpy(train.buff, "1");
    train.len = 1;
    // 返回客户端校验结果
    send(net_fd, &train, sizeof(train.len) + sizeof(train.type) + train.len, MSG_NOSIGNAL);
    printf("user %s login.\n", username);
    bzero(logged_in_username, strlen(logged_in_username));
    strcpy(logged_in_username, username);
    return 0;
}


//子线程调用:处理客户端发过来的消息
int handleMessage(task_t *task) {
    int sockfd = task->peerfd;

    // 消息格式：train_t 
    train_t train;
    bzero(&train, sizeof(train));

    // 接收消息类型
    recv(sockfd, &train, sizeof(train.len) + sizeof(train.type), MSG_WAITALL);
    CmdType cmdType = train.type;
    printf("received operation: %d\n", cmdType);
    // 根据消息类型执行对应操作
    switch (cmdType) {
        case CMD_TYPE_LS:
            lsCommand(task);
            break;
        case CMD_TYPE_CD:
            cdCommand(task);
            break;
        case CMD_TYPE_PWD:
            pwdCommand(task);
            break;
        case CMD_TYPE_MKDIR:
            mkdirCommand(task);
            break;
        case CMD_TYPE_RMDIR:
            rmdirCommand(task);
            break;
        case CMD_TYPE_PUTS:
            putsCommand(task);
            break;
        case CMD_TYPE_GETS:
            getsCommand(task);
            break;
        default:
            notCommand(task);
            break;
    }

    return 1; // 继续处理下一个消息
}

void lsCommand(task_t *task) {
    int sockfd = task->peerfd;
    const char *current_dir = task->current_dir;

    // 列出当前目录下的文件
    DIR *dir;
    struct dirent *entry;
    dir = opendir(current_dir);
    if (dir == NULL) {
        perror("opendir");
        int len = strlen("Failed to open directory");
        sendn(sockfd, &len, sizeof(int));
        sendn(sockfd, "Failed to open directory", len);
        return;
    }

    while ((entry = readdir(dir)) != NULL) {
        int len = strlen(entry->d_name);
        sendn(sockfd, &len, sizeof(int));
        sendn(sockfd, entry->d_name, len);
    }
    // 发送长度为 0 表示结束
    int end_len = 0;
    sendn(sockfd, &end_len, sizeof(int));
    closedir(dir);
}

void cdCommand(task_t *task) {
    int sockfd = task->peerfd;
    char *new_dir = task->data;
    char *current_dir = task->current_dir;

    char path[1024];
    snprintf(path, sizeof(path), "%s/%s", current_dir, new_dir);

    if (chdir(path) == 0) {
        strcpy(current_dir, path);
        int len = strlen("Directory changed successfully");
        sendn(sockfd, &len, sizeof(int));
        sendn(sockfd, "Directory changed successfully", len);
    } else {
        int len = strlen("Failed to change directory");
        sendn(sockfd, &len, sizeof(int));
        sendn(sockfd, "Failed to change directory", len);
    }
}

void pwdCommand(task_t *task) {
    int sockfd = task->peerfd;
    const char *current_dir = task->current_dir;

    int len = strlen(current_dir);
    sendn(sockfd, &len, sizeof(int));
    sendn(sockfd, current_dir, len);
}

void mkdirCommand(task_t *task) {
    int sockfd = task->peerfd;
    char *dir_name = task->data;

    if (mkdir(dir_name, 0777) == 0) {
        int len = strlen("Directory created successfully");
        sendn(sockfd, &len, sizeof(int));
        sendn(sockfd, "Directory created successfully", len);
    } else {
        int len = strlen("Failed to create directory");
        sendn(sockfd, &len, sizeof(int));
        sendn(sockfd, "Failed to create directory", len);
    }
}

void rmdirCommand(task_t *task) {
    int sockfd = task->peerfd;
    char *dir_name = task->data;

    if (rmdir(dir_name) == 0) {
        int len = strlen("Directory removed successfully");
        sendn(sockfd, &len, sizeof(int));
        sendn(sockfd, "Directory removed successfully", len);
    } else {
        int len = strlen("Failed to remove directory");
        sendn(sockfd, &len, sizeof(int));
        sendn(sockfd, "Failed to remove directory", len);
    }
}

void notCommand(task_t *task) {
    int sockfd = task->peerfd;

    int len = strlen("Unknown command");
    sendn(sockfd, &len, sizeof(int));
    sendn(sockfd, "Unknown command", len);
}

void putsCommand(task_t *task) {
    int sockfd = task->peerfd;
    const char *current_dir = task->current_dir;
    char *filename = task->data;

    char full_path[1024];
    snprintf(full_path, sizeof(full_path), "%s/%s", current_dir, filename);

    int fd = open(full_path, O_RDWR | O_CREAT, 0666);
    if (fd == -1) {
        perror("open");
        int len = strlen("Failed to open file");
        sendn(sockfd, &len, sizeof(int));
        sendn(sockfd, "Failed to open file", len);
        return;
    }

    // 接收文件大小
    off_t file_size;
    int data_len;
    recvn(sockfd, &data_len, sizeof(int));
    recvn(sockfd, &file_size, data_len);

    // 接收文件内容
    void *pstart = mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (pstart == (void *)-1) {
        perror("mmap");
        close(fd);
        int len = strlen("Failed to mmap file");
        sendn(sockfd, &len, sizeof(int));
        sendn(sockfd, "Failed to mmap file", len);
        return;
    }

    recvn(sockfd, pstart, file_size);
    munmap(pstart, file_size);
    close(fd);

    int len = strlen("File uploaded successfully");
    sendn(sockfd, &len, sizeof(int));
    sendn(sockfd, "File uploaded successfully", len);
}

void getsCommand(task_t *task) {
    int sockfd = task->peerfd;
    const char *current_dir = task->current_dir;
    char *filename = task->data;

    char full_path[1024];
    snprintf(full_path, sizeof(full_path), "%s/%s", current_dir, filename);

    int fd = open(full_path, O_RDONLY);
    if (fd == -1) {
        perror("open");
        int len = strlen("Failed to open file");
        sendn(sockfd, &len, sizeof(int));
        sendn(sockfd, "Failed to open file", len);
        return;
    }

    // 获取文件大小
    off_t file_size = lseek(fd, 0, SEEK_END);
    lseek(fd, 0, SEEK_SET);

    // 发送文件大小
    int data_len = sizeof(off_t);
    sendn(sockfd, &data_len, sizeof(int));
    sendn(sockfd, &file_size, data_len);

    // 发送文件内容
    void *pstart = mmap(NULL, file_size, PROT_READ, MAP_SHARED, fd, 0);
    if (pstart == (void *)-1) {
        perror("mmap");
        close(fd);
        int len = strlen("Failed to mmap file");
        sendn(sockfd, &len, sizeof(int));
        sendn(sockfd, "Failed to mmap file", len);
        return;
    }

    sendn(sockfd, pstart, file_size);
    munmap(pstart, file_size);
    close(fd);
}
